home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / dragsource.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-29  |  24.6 KB  |  1,084 lines

  1.  
  2.  
  3. #include <X11/Xatom.h>
  4. #include <math.h>
  5.  
  6. #include "WINGsP.h"
  7.  
  8.  
  9.  
  10.  
  11. #define SPIT(a) puts(a)
  12.  
  13.  
  14. #define IS_DROPPABLE(view) (view!=NULL && view->droppableTypes!=NULL && \
  15.                 view->dragDestinationProcs!=NULL)
  16.  
  17.  
  18. static Bool _XErrorOccured = False;
  19.  
  20.  
  21.  
  22.  
  23. void
  24. WMSetViewDragSourceProcs(WMView *view, WMDragSourceProcs *procs)
  25. {
  26.     if (view->dragSourceProcs)
  27.     free(view->dragSourceProcs);
  28.     view->dragSourceProcs = wmalloc(sizeof(WMDragSourceProcs));
  29.     
  30.     *view->dragSourceProcs = *procs;
  31.     
  32.     /* XXX fill in non-implemented stuffs */
  33. }
  34.  
  35.  
  36. /***********************************************************************/
  37.  
  38.  
  39. static int
  40. handleXError(Display *dpy, XErrorEvent *ev)
  41. {
  42.     _XErrorOccured = True;
  43.     
  44.     return 1;
  45. }
  46.  
  47.  
  48. static void
  49. protectBlock(Bool begin)
  50. {
  51.     static void *oldHandler = NULL;
  52.     
  53.     if (begin) {
  54.     oldHandler = XSetErrorHandler(handleXError);
  55.     } else {
  56.     XSetErrorHandler(oldHandler);
  57.     }
  58. }
  59.  
  60.  
  61.  
  62.  
  63. static Window
  64. makeDragIcon(WMScreen *scr, WMPixmap *pixmap)
  65. {
  66.     Window window;
  67.     WMSize size;
  68.     unsigned long flags;
  69.     XSetWindowAttributes attribs;
  70.     Pixmap pix, mask;
  71.     
  72.     if (!pixmap) {
  73.     pixmap = scr->defaultObjectIcon;
  74.     }
  75.     size = WMGetPixmapSize(pixmap);
  76.     pix = pixmap->pixmap;
  77.     mask = pixmap->mask;
  78.  
  79.     flags = CWSaveUnder|CWBackPixmap|CWOverrideRedirect|CWColormap;
  80.     attribs.save_under = True;
  81.     attribs.background_pixmap = pix;
  82.     attribs.override_redirect = True;
  83.     attribs.colormap = scr->colormap;
  84.     window = XCreateWindow(scr->display, scr->rootWin, 0, 0, size.width,
  85.                size.height, 0, scr->depth, InputOutput,
  86.                scr->visual, flags, &attribs);
  87.  
  88. #ifdef SHAPE
  89.     if (mask) {
  90.     XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, mask,
  91.               ShapeSet);
  92.     }
  93. #endif
  94.  
  95.     return window;
  96. }
  97.  
  98.  
  99. static void
  100. slideWindow(Display *dpy, Window win, int srcX, int srcY, int dstX, int dstY)
  101. {
  102.     double x, y, dx, dy;
  103.     int i;
  104.     int iterations;
  105.  
  106.     iterations = WMIN(25, WMAX(abs(dstX-srcX), abs(dstY-srcY)));
  107.     
  108.     x = srcX;
  109.     y = srcY;
  110.     
  111.     dx = (double)(dstX-srcX)/iterations;
  112.     dy = (double)(dstY-srcY)/iterations;
  113.  
  114.     for (i = 0; i <= iterations; i++) {
  115.     XMoveWindow(dpy, win, x, y);
  116.         XFlush(dpy);
  117.         
  118.     wusleep(800);
  119.     
  120.         x += dx;
  121.         y += dy;
  122.     }
  123. }
  124.  
  125.  
  126. static Window
  127. findChildInWindow(Display *dpy, Window toplevel, int x, int y)
  128. {
  129.     Window foo, bar;
  130.     Window *children;
  131.     unsigned nchildren;
  132.     int i;
  133.         
  134.     if (!XQueryTree(dpy, toplevel, &foo, &bar,
  135.             &children, &nchildren) || children == NULL) {
  136.     return None;
  137.     }
  138.     
  139.     /* first window that contains the point is the one */
  140.     for (i = nchildren-1; i >= 0; i--) {
  141.     XWindowAttributes attr;
  142.  
  143.     if (XGetWindowAttributes(dpy, children[i], &attr)
  144.         && attr.map_state == IsViewable
  145.         && x >= attr.x && y >= attr.y
  146.         && x < attr.x + attr.width && y < attr.y + attr.height) {
  147.         Window child;
  148.         
  149.         child = findChildInWindow(dpy, children[i], 
  150.                       x - attr.x, y - attr.y);
  151.  
  152.         XFree(children);
  153.         
  154.         if (child == None)
  155.         return toplevel;
  156.         else
  157.         return child;
  158.     }
  159.     }
  160.  
  161.     XFree(children);
  162.     return None;
  163. }
  164.  
  165.  
  166. static WMView*
  167. findViewInToplevel(Display *dpy, Window toplevel, int x, int y)
  168. {
  169.     Window child;
  170.  
  171.     child = findChildInWindow(dpy, toplevel, x, y);
  172.     
  173.     if (child != None)
  174.     return W_GetViewForXWindow(dpy, child);
  175.     else
  176.     return NULL;
  177. }
  178.  
  179.  
  180.  
  181. static Window
  182. lookForToplevel(WMScreen *scr, Window window, Bool *isAware)
  183. {
  184.     Window toplevel = None;
  185.     Atom *atoms;
  186.     int j, count;
  187.     
  188.     *isAware = False;
  189.     
  190.     atoms = XListProperties(scr->display, window, &count);
  191.     for (j = 0; j < count; j++) {
  192.     if (atoms[j] == scr->wmStateAtom) {
  193.         toplevel = window;
  194.     } else if (atoms[j] == scr->xdndAwareAtom) {
  195.         *isAware = True;
  196.     }
  197.     }
  198.     if (atoms)
  199.     XFree(atoms);
  200.  
  201.     if (toplevel == None) {
  202.     Window *children;
  203.     Window foo, bar;
  204.     unsigned nchildren;
  205.     
  206.     if (!XQueryTree(scr->display, window, &foo, &bar,
  207.             &children, &nchildren) || children == NULL) {
  208.         return None;
  209.     }
  210.     
  211.     for (j = 0; j < nchildren; j++) {
  212.         toplevel = lookForToplevel(scr, children[j], isAware);
  213.         if (toplevel != None)
  214.         break;
  215.     }
  216.     
  217.     XFree(children);
  218.     
  219.     
  220.     }
  221.     
  222.     return toplevel;
  223. }
  224.  
  225.  
  226.     
  227. static Window
  228. findToplevelUnderDragPointer(WMScreen *scr, int x, int y, Window iconWindow)
  229. {
  230.     Window foo, bar;
  231.     Window *children;
  232.     unsigned nchildren;
  233.     Bool overSomething = False;
  234.     int i;
  235.  
  236.     if (!XQueryTree(scr->display, scr->rootWin, &foo, &bar,
  237.             &children, &nchildren) || children == NULL) {
  238.     SPIT("couldnt query tree!");
  239.     return None;
  240.     }
  241.     
  242.     /* try to find the window below the iconWindow by traversing
  243.      * the whole window list */
  244.  
  245.     /* first find the position of the iconWindow */
  246.     for (i = nchildren-1; i >= 0; i--) {
  247.     if (children[i] == iconWindow) {
  248.         i--;
  249.         break;
  250.     }
  251.     }
  252.     if (i <= 0) {
  253.     XFree(children);
  254.     return scr->rootWin;
  255.     }
  256.  
  257.     /* first window that contains the point is the one */
  258.     for (; i >= 0; i--) {
  259.     XWindowAttributes attr;
  260.  
  261.     if (XGetWindowAttributes(scr->display, children[i], &attr)
  262.         && attr.map_state == IsViewable
  263.         && x >= attr.x && y >= attr.y
  264.         && x < attr.x + attr.width && y < attr.y + attr.height) {
  265.         Window toplevel;
  266.         Bool isaware;
  267.         
  268.         overSomething = True;
  269.         
  270.         toplevel = lookForToplevel(scr, children[i], &isaware);
  271.         
  272.         XFree(children);
  273.         
  274.         if (isaware)
  275.         return toplevel;
  276.         else
  277.         return None;
  278.     }
  279.     }
  280.  
  281.     XFree(children);
  282.     if (!overSomething)
  283.     return scr->rootWin;
  284.     else
  285.     return None;
  286. }
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293. static void
  294. sendClientMessage(Display *dpy, Window win, Atom message,
  295.           unsigned data1, unsigned data2, unsigned data3,
  296.           unsigned data4, unsigned data5)
  297. {
  298.     XEvent ev;
  299.     
  300.     ev.type = ClientMessage;
  301.     ev.xclient.message_type = message;
  302.     ev.xclient.format = 32;
  303.     ev.xclient.window = win;
  304.     ev.xclient.data.l[0] = data1;
  305.     ev.xclient.data.l[1] = data2;
  306.     ev.xclient.data.l[2] = data3;
  307.     ev.xclient.data.l[3] = data4;
  308.     ev.xclient.data.l[4] = data5;
  309.  
  310.     XSendEvent(dpy, win, False, 0, &ev);
  311.     XFlush(dpy);
  312. }
  313.  
  314.  
  315.  
  316.  
  317. static unsigned
  318. notifyPosition(WMScreen *scr, WMDraggingInfo *info)
  319. {
  320.     unsigned operation;
  321.     
  322.     switch (info->sourceOperation) {
  323.      default:
  324.     operation = None;
  325.     break;
  326.     }
  327.  
  328.     sendClientMessage(scr->display, info->destinationWindow, 
  329.               scr->xdndPositionAtom,
  330.               info->sourceWindow, 
  331.               0, /* reserved */
  332.               info->location.x<<16|info->location.y,
  333.               info->timestamp, 
  334.               operation/* operation */);
  335.     
  336.     return 0;
  337. }
  338.  
  339.  
  340.  
  341. static void
  342. notifyDrop(WMScreen *scr, WMDraggingInfo *info)
  343. {
  344.     sendClientMessage(scr->display, info->destinationWindow,
  345.               scr->xdndDropAtom,
  346.               info->sourceWindow, 
  347.               0, /* reserved */
  348.               info->timestamp,
  349.               0, 0);
  350. }
  351.  
  352.  
  353.  
  354. static void
  355. notifyDragLeave(WMScreen *scr, WMDraggingInfo *info)
  356. {    
  357.     sendClientMessage(scr->display, info->destinationWindow,
  358.               scr->xdndLeaveAtom,
  359.               info->sourceWindow, 0, 0, 0, 0);
  360. }
  361.  
  362.  
  363.  
  364. static unsigned
  365. notifyDragEnter(WMScreen *scr, WMDraggingInfo *info)
  366. {
  367.     unsigned d;
  368.     
  369.     d = XDND_VERSION << 24;
  370.     
  371.     sendClientMessage(scr->display, info->destinationWindow,
  372.               scr->xdndEnterAtom,
  373.               info->sourceWindow, d, 0, 0, 0);
  374.     
  375.     return 0;
  376. }
  377.  
  378.  
  379. static void
  380. translateCoordinates(WMScreen *scr, Window target, int fromX, int fromY,
  381.              int *x, int *y)
  382. {
  383.     Window child;
  384.     
  385.     XTranslateCoordinates(scr->display, scr->rootWin, target,
  386.               fromX, fromY, x, y, &child);
  387. }
  388.  
  389.  
  390. static void
  391. updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info,
  392.            XEvent *event, Window iconWindow)
  393. {
  394.     Window toplevel;
  395.     WMSize size;
  396.     
  397.     size = WMGetPixmapSize(info->image);
  398.  
  399.     if (event->type == MotionNotify) {
  400.     info->imageLocation.x = event->xmotion.x_root-(int)size.width/2;
  401.     info->imageLocation.y = event->xmotion.y_root-(int)size.height/2;
  402.         
  403.     info->location.x = event->xmotion.x_root;
  404.     info->location.y = event->xmotion.y_root;
  405.     info->timestamp = event->xmotion.time;
  406.     
  407.     } else if (event->type == ButtonRelease) {
  408.     info->imageLocation.x = event->xbutton.x_root-(int)size.width/2;
  409.     info->imageLocation.y = event->xbutton.y_root-(int)size.height/2;
  410.         
  411.     info->location.x = event->xbutton.x_root;
  412.     info->location.y = event->xbutton.y_root;
  413.     info->timestamp = event->xbutton.time;
  414.     }
  415.  
  416.     toplevel = findToplevelUnderDragPointer(scr,
  417.                         info->location.x,
  418.                         info->location.y,
  419.                         iconWindow);
  420.     info->destinationWindow = toplevel;
  421.     /*
  422.     if (toplevel == None) {
  423.     info->destinationWindow = None;
  424.     } else if (toplevel == scr->rootWin) {
  425.     info->destinationWindow = scr->rootWin;
  426.     } else {
  427.     Window child;
  428.     int x, y;
  429.     
  430.     XTranslateCoordinates(scr->display, scr->rootWin, toplevel,
  431.                   info->location.x, info->location.y,
  432.                   &x, &y, &child);
  433.  
  434.     child = findChildInWindow(scr->display, toplevel, x, y);
  435.  
  436.     if (child != None) {
  437.         info->destination = W_GetViewForXWindow(scr->display, child);
  438.         if (info->destination->droppableTypes == NULL) {
  439.         info->destination = NULL;
  440.         } else if (info->destination->dragDestinationProcs == NULL) {
  441.         info->destination = NULL;
  442.         }
  443.     } else {
  444.         info->destination = NULL;
  445.     }
  446.     info->destinationWindow = toplevel;
  447.     }
  448.     */
  449. }
  450.  
  451.  
  452.  
  453.  
  454. static void
  455. processMotion(WMScreen *scr, WMDraggingInfo *info, WMDraggingInfo *oldInfo,
  456.           WMRect *rect, unsigned currentAction)
  457. {
  458.     unsigned action;
  459.     
  460.     if (info->destinationWindow == None) { /* entered an unsupporeted window */
  461.  
  462.     if (oldInfo->destinationWindow != None
  463.         && oldInfo->destinationWindow != scr->rootWin) {
  464.         SPIT("left window");
  465.         
  466.         notifyDragLeave(scr, oldInfo);
  467.     }
  468.  
  469.     } else if (info->destinationWindow == scr->rootWin) {
  470.  
  471.     if (oldInfo->destinationWindow != None
  472.         && oldInfo->destinationWindow != scr->rootWin) {
  473.         SPIT("left window to root");
  474.         
  475.         notifyDragLeave(scr, oldInfo);
  476.     } else {
  477.         /* nothing */
  478.     }
  479.  
  480.     } else if (oldInfo->destinationWindow != info->destinationWindow) {
  481.  
  482.     if (oldInfo->destinationWindow != None
  483.         && oldInfo->destinationWindow != scr->rootWin) {
  484.         notifyDragLeave(scr, oldInfo);
  485.         SPIT("crossed");
  486.     } else {
  487.         SPIT("entered window");
  488.     }
  489.  
  490.     action = notifyDragEnter(scr, info);
  491.  
  492.     } else {
  493.  
  494. #define LEFT_RECT(r, X, Y) (X < r->pos.x || Y < r->pos.y \
  495.                 || X >= r->pos.x + r->size.width \
  496.                 || Y >= r->pos.y + r->size.height)
  497.  
  498.     if (rect->size.width == 0 ||
  499.         (LEFT_RECT(rect, info->location.x, info->location.y))) {
  500.  
  501.         action = notifyPosition(scr, info);
  502.  
  503.         rect->size.width = 0;
  504.     }
  505.     }
  506.     
  507.     /* little trick to simulate XdndStatus for local dnd */
  508.     /*
  509.     if (bla && action != currentAction) {
  510.     XEvent ev;
  511.  
  512.     ev.type = ClientMessage;
  513.     ev.xclient.display = scr->display;
  514.     ev.xclient.message_type = scr->xdndStatusAtom;
  515.     ev.xclient.format = 32;
  516.     ev.xclient.window = info->destinationWindow;
  517.     ev.xclient.data.l[0] = info->sourceWindow;
  518.     ev.xclient.data.l[1] = (action ? 1 : 0);
  519.     ev.xclient.data.l[2] = 0;
  520.     ev.xclient.data.l[3] = 0;
  521.     ev.xclient.data.l[4] = action;
  522.     
  523.     XPutBackEvent(scr->display, &ev);
  524.     }*/
  525. }
  526.  
  527.  
  528.  
  529.  
  530. static void
  531. timeoutCallback(void *data)
  532. {
  533.     wwarning("drag & drop timed out while waiting for response from 0x%x\n",
  534.          (unsigned)data);
  535.     _XErrorOccured = 1;
  536. }
  537.  
  538. /*
  539.  * State Machine For Drag Source:
  540.  * ------------------------------
  541.  *                              Events
  542.  * State                Call  Mtn   Ent   Lea   Crs   BUp   StA   StR   Fin   TO
  543.  * 0) idle        1bu   -     -     -     -     -     -     -     -     -
  544.  * 1) drag over target  -     1au   -     2cu   1cbu  5fu   3     4     1w    -
  545.  * 2) drag over nothing -     2     1bu   -     -     0     -     -     2w    -
  546.  * 3) drag targ+accept  -     3u    -     2cu   1cbu  6f    3     4w    0z    -
  547.  * 4) drag targ+reject  -     4u    -     2cu   1cbu  0     3w    4     0z    -
  548.  * 5) waiting status    -     5X    5X    5X    5X    -     6f    0     0z    0w
  549.  * 6) dropped        -     -     -     -     -     -     -     -     0     0w
  550.  * 
  551.  * Events:
  552.  * Call - called WMDragImageFromView()
  553.  * Mtn - Motion
  554.  * Ent - Enter droppable window
  555.  * Lea - Leave droppable window (or rectangle)
  556.  * Crs - Leave droppable window (or rectangle) and enter another
  557.  * BUp - Button Released
  558.  * StA - XdndStatus client msg with Accept drop
  559.  * StR - XdndStatus client msg with Reject drop
  560.  * Fin - XdndFinish client msg
  561.  * TO  - timeout
  562.  * 
  563.  * Actions:
  564.  * a - send update message
  565.  * b - send enter message
  566.  * c - send leave message
  567.  * d - release drag section info
  568.  * e - send drop message
  569.  * f - setup timeout
  570.  * u - update dragInfo
  571.  * 
  572.  * X - ignore
  573.  * w - warn about unexpected reply
  574.  * z - abort operation.. unexpected reply
  575.  * -   shouldnt happen
  576.  */
  577. void
  578. WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
  579.             WMPoint atLocation, WMSize mouseOffset, XEvent *event,
  580.             Bool slideBack)
  581. {
  582.     WMScreen *scr = view->screen;
  583.     Display *dpy = scr->display;
  584.     Window icon;
  585.     XEvent ev;
  586.     WMSize size;
  587.     WMRect rect = {{0,0},{0,0}};
  588.     int ostate = -1;
  589.     int state;
  590.     int action = -1;
  591.     XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue};
  592.     XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue};
  593.     XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue};
  594.     WMDraggingInfo dragInfo;
  595.     WMDraggingInfo oldDragInfo;
  596.     WMHandlerID timer = NULL;
  597.     WMData *draggedData = NULL;
  598.  
  599.     
  600.     wassertr(view->dragSourceProcs != NULL);
  601.  
  602.     
  603.     /* prepare icon to be dragged */
  604.     if (image == NULL)
  605.     image = scr->defaultObjectIcon;
  606.  
  607.     size = WMGetPixmapSize(image);
  608.  
  609.     icon = makeDragIcon(scr, image);
  610.  
  611.     XMoveWindow(dpy, icon, event->xmotion.x_root-(int)size.width/2,
  612.         event->xmotion.y_root-(int)size.height/2);
  613.     XMapRaised(dpy, icon);
  614.     
  615.  
  616.     /* init dragging info */
  617.     memset(&dragInfo, 0, sizeof(WMDraggingInfo));
  618.     memset(&oldDragInfo, 0, sizeof(WMDraggingInfo));
  619.     dragInfo.image = image;
  620.     dragInfo.sourceWindow = W_VIEW_DRAWABLE(W_TopLevelOfView(view));
  621.  
  622.     dragInfo.destinationWindow = dragInfo.sourceWindow;
  623.  
  624.     dragInfo.location.x = event->xmotion.x_root;
  625.     dragInfo.location.y = event->xmotion.y_root;
  626.     dragInfo.imageLocation = atLocation;
  627.     
  628.     
  629.     /* start pointer grab */
  630.     XGrabPointer(dpy, scr->rootWin, False,
  631.          ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,
  632.          GrabModeSync, GrabModeAsync, None, scr->defaultCursor,
  633.          CurrentTime);
  634.  
  635.     XFlush(dpy);
  636.  
  637.     _XErrorOccured = False;
  638.     
  639.     /* XXX: take ownership of XdndSelection */
  640.  
  641.     
  642.     if (view->dragSourceProcs->beganDragImage != NULL) {
  643.     view->dragSourceProcs->beganDragImage(view, image, atLocation);
  644.     }
  645.  
  646.     processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
  647.  
  648.     state = 1;
  649.  
  650.     while (state != 6 && state != 0 && !_XErrorOccured) {
  651.     XAllowEvents(dpy, SyncPointer, CurrentTime);
  652.     WMNextEvent(dpy, &ev);
  653.  
  654.     switch (ev.type) {
  655.      case MotionNotify:
  656.         if (state >= 1 && state <= 4) {
  657.         while (XCheckTypedEvent(dpy, MotionNotify, &ev)) ;
  658.  
  659.         protectBlock(True);
  660.  
  661.         oldDragInfo = dragInfo;
  662.  
  663.         updateDraggingInfo(scr, &dragInfo, &ev, icon);
  664.  
  665.         XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
  666.                 dragInfo.imageLocation.y);
  667.  
  668.         if (state != 2) {
  669.             processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
  670.         }
  671.         protectBlock(False);
  672.  
  673.         /* XXXif entered a different destination, check the operation */
  674.  
  675.         switch (state) {
  676.          case 1:
  677.             if (oldDragInfo.destinationWindow != None
  678.              && (dragInfo.destinationWindow == None
  679.                  || dragInfo.destinationWindow == scr->rootWin)) {
  680.             /* left the droppable window */
  681.             state = 2;
  682.             action = -1;
  683.             }
  684.             break;
  685.             
  686.          case 2:
  687.             if (dragInfo.destinationWindow != None) {
  688.             state = 1;
  689.             action = -1;
  690.             }
  691.             break;
  692.  
  693.          case 3:
  694.          case 4:
  695.             if (oldDragInfo.destinationWindow != None
  696.              && (dragInfo.destinationWindow == None
  697.                  || dragInfo.destinationWindow == scr->rootWin)) {
  698.             /* left the droppable window */
  699.             state = 2;
  700.             action = -1;
  701.             }
  702.             break;
  703.         }
  704.         }
  705.         break;
  706.         
  707.  
  708.      case ButtonRelease:
  709.         /* if (state >= 1 && state <= 4) */ {
  710.         
  711.         protectBlock(True);
  712.         
  713.         oldDragInfo = dragInfo;
  714.  
  715.         updateDraggingInfo(scr, &dragInfo, &ev, icon);
  716.         
  717.         XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
  718.                 dragInfo.imageLocation.y);
  719.  
  720.         processMotion(scr, &dragInfo, &oldDragInfo, &rect,
  721.                   action);
  722.  
  723.         protectBlock(False);
  724.         
  725.         switch (state) {
  726.          case 1:
  727.             state = 5;
  728.             timer = WMAddTimerHandler(3000, timeoutCallback,
  729.                           (void*)dragInfo.destinationWindow);
  730.             break;
  731.          case 2:
  732.             state = 0;
  733.             break;
  734.          case 3:
  735.             state = 6;
  736.             break;
  737.          case 4:
  738.             state = 0;
  739.             break;
  740.         }
  741.         }
  742.         break;
  743.  
  744.  
  745.      case SelectionRequest:
  746.         
  747.         draggedData = NULL;
  748.         
  749.         break;
  750.  
  751.      case ClientMessage:
  752.         if ((state == 1 || state == 3 || state == 4 || state == 5)
  753.         && ev.xclient.message_type == scr->xdndStatusAtom
  754.         && ev.xclient.window == dragInfo.destinationWindow) {
  755.  
  756.         if (ev.xclient.data.l[1] & 1) {
  757.             puts("got accept msg");
  758.             /* will accept drop */
  759.             switch (state) {
  760.              case 1:
  761.              case 3:
  762.              case 4:
  763.             state = 3;
  764.             break;
  765.              case 5:
  766.             if (timer) {
  767.                 WMDeleteTimerHandler(timer);
  768.                 timer = NULL;
  769.             }
  770.             state = 6;
  771.             break;
  772.             }
  773.             if (ev.xclient.data.l[4] == None) {
  774.             action = 0;
  775.             } else {
  776.             action = ev.xclient.data.l[4];/*XXX*/
  777.             }
  778.         } else {
  779.             puts("got reject msg");
  780.             switch (state) {
  781.              case 1:
  782.              case 3:
  783.              case 4:
  784.             state = 4;
  785.             break;
  786.              case 5:
  787.             state = 0;
  788.             if (timer) {
  789.                 WMDeleteTimerHandler(timer);
  790.                 timer = NULL;
  791.             }
  792.             break;
  793.             }
  794.             action = 0;
  795.         }
  796.  
  797.         if (ev.xclient.data.l[1] & (1<<1)) {
  798.             rect.pos.x = ev.xclient.data.l[2] >> 16;
  799.             rect.pos.y = ev.xclient.data.l[2] & 0xffff;
  800.             rect.size.width = ev.xclient.data.l[3] >> 16;
  801.             rect.size.height = ev.xclient.data.l[3] & 0xffff;
  802.         } else {
  803.             rect.size.width = 0;
  804.         }
  805.                 
  806.         } else if ((state >= 1 && state <= 5)
  807.                && ev.xclient.message_type == scr->xdndFinishedAtom
  808.                && ev.xclient.window == dragInfo.destinationWindow) {
  809.  
  810.         wwarning("drag source received unexpected XdndFinished message from %x",
  811.              (unsigned)dragInfo.destinationWindow);
  812.  
  813.         if (state == 3 || state == 4 || state == 5) {
  814.             state = 0;
  815.             if (timer) {
  816.             WMDeleteTimerHandler(timer);
  817.             timer = NULL;
  818.             }
  819.         }
  820.         }
  821.         
  822.      default:
  823.         WMHandleEvent(&ev);
  824.         break;
  825.     }
  826.     
  827.     if (ostate != state) {
  828.         printf("state changed to %i\n", state);
  829.         if (state == 3) {
  830.         XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
  831.         } else if (ostate == 3) {
  832.         XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
  833.         }
  834.         ostate = state;
  835.     }
  836.     }
  837.  
  838.     if (timer) {
  839.     WMDeleteTimerHandler(timer);
  840.     timer = NULL;
  841.     }
  842.  
  843.     XUngrabPointer(dpy, CurrentTime);
  844.     
  845.     SPIT("exited main loop");
  846.  
  847.     if (_XErrorOccured || state != 6) {
  848.     goto cancelled;
  849.     }
  850.  
  851.     assert(dragInfo.destinationWindow != None);
  852.     
  853.     protectBlock(True);
  854.     notifyDrop(scr, &dragInfo);
  855.     protectBlock(False);
  856.     
  857.     if (_XErrorOccured)
  858.     goto cancelled;
  859.     
  860.     
  861.     SPIT("dropped");
  862.     /* wait for Finished message and SelectionRequest if not a local drop */
  863.     
  864.     
  865.  
  866.     XDestroyWindow(dpy, icon);
  867.     if (view->dragSourceProcs->endedDragImage != NULL) {
  868.     view->dragSourceProcs->endedDragImage(view, image, 
  869.                           dragInfo.imageLocation,
  870.                           True);
  871.     }
  872.     return;
  873.  
  874. cancelled:
  875.     if (draggedData) {
  876.     WMReleaseData(draggedData);
  877.     }
  878.     
  879.     if (slideBack) {
  880.     slideWindow(dpy, icon,
  881.             dragInfo.imageLocation.x, dragInfo.imageLocation.y,
  882.             atLocation.x, atLocation.y);
  883.     }
  884.     XDestroyWindow(dpy, icon);
  885.     if (view->dragSourceProcs->endedDragImage != NULL) {
  886.     view->dragSourceProcs->endedDragImage(view, image, 
  887.                           dragInfo.imageLocation,
  888.                           False);
  889.     }
  890. }
  891.  
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901.  
  902.  
  903.  
  904.  
  905.  
  906.  
  907.  
  908.  
  909. static Atom*
  910. getTypeList(Window window, XClientMessageEvent *event)
  911. {
  912.     int i = 0;
  913.     Atom *types = NULL;
  914.     
  915.     if (event->data.l[1] & 1) { /* > 3 types */
  916.         
  917.     } else {
  918.     types = wmalloc(4 * sizeof(Atom));
  919.     if (event->data.l[2] != None)
  920.         types[i++] = event->data.l[2];
  921.     if (event->data.l[3] != None)
  922.         types[i++] = event->data.l[3];
  923.     if (event->data.l[4] != None)
  924.         types[i++] = event->data.l[4];
  925.     types[i] = 0;
  926.     }
  927.     
  928.     if (types[0] == 0) {
  929.     wwarning("received invalid drag & drop type list");
  930.     /*XXX        return;*/
  931.     }
  932.  
  933.     return types;
  934. }
  935.  
  936.  
  937. void
  938. W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
  939. {
  940. #if 0
  941.     WMScreen *scr = W_VIEW_SCREEN(toplevel);
  942.     WMView *oldView = NULL, *newView = NULL;
  943.     unsigned operation = 0;
  944.     int x, y;
  945.  
  946.     if (event->message_type == scr->xdndEnterAtom) {
  947.     Window foo, bar;
  948.     int bla;
  949.     unsigned ble;
  950.     puts("entered");
  951.     
  952.     if (scr->dragInfo.sourceWindow != None) {
  953.         puts("received Enter event in bad order");
  954.     }
  955.     
  956.     memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo));
  957.     
  958.     
  959.     if ((event->data.l[0] >> 24) > XDND_VERSION) {
  960.         wwarning("received drag & drop request with unsupported version %i",
  961.             (event->data.l[0] >> 24));
  962.         return;
  963.     }
  964.     
  965.     scr->dragInfo.protocolVersion = event->data.l[1] >> 24;
  966.     scr->dragInfo.sourceWindow = event->data.l[0];
  967.     scr->dragInfo.destinationWindow = event->window;
  968.     
  969.     /* XXX */
  970.     scr->dragInfo.image = NULL;
  971.     
  972.     XQueryPointer(scr->display, scr->rootWin, &foo, &bar,
  973.               &scr->dragInfo.location.x, &scr->dragInfo.location.y,
  974.               &bla, &bla, &ble);
  975.  
  976.     translateCoordinates(scr, scr->dragInfo.destinationWindow,
  977.                  scr->dragInfo.location.x,
  978.                  scr->dragInfo.location.y, &x, &y);
  979.  
  980.  
  981.     newView = findViewInToplevel(scr->display,
  982.                    scr->dragInfo.destinationWindow, 
  983.                   x, y);
  984.     
  985.     if (IS_DROPPABLE(view)) {
  986.         
  987.         scr->dragInfo.destinationView = view;
  988.         
  989.         operation =
  990.         view->dragDestinationProcs->draggingEntered(view, 
  991.                                 &scr->dragInfo);
  992.     }
  993.     if (operation > 0) {
  994.         Atom action;
  995.         
  996.         switch (operation) {
  997.          default:
  998.         action = 0;
  999.         break;
  1000.         }
  1001.  
  1002.         sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
  1003.                   scr->xdndStatusAtom,
  1004.                   scr->dragInfo.destinationWindow,
  1005.                   1, 0, 0, action);
  1006.     }
  1007.  
  1008.     } else if (event->message_type == scr->xdndPositionAtom
  1009.            && scr->dragInfo.sourceWindow == event->data.l[0]) {
  1010.     
  1011.     scr->dragInfo.location.x = event->data.l[2] >> 16;
  1012.     scr->dragInfo.location.y = event->data.l[2] & 0xffff;
  1013.     
  1014.     if (scr->dragInfo.protocolVersion >= 1) {
  1015.         scr->dragInfo.timestamp = event->data.l[3];
  1016.         scr->dragInfo.sourceOperation = event->data.l[4];
  1017.     } else {
  1018.         scr->dragInfo.timestamp = CurrentTime;
  1019.         scr->dragInfo.sourceOperation = 0; /*XXX*/
  1020.     }
  1021.  
  1022.     translateCoordinates(scr, scr->dragInfo.destinationWindow,
  1023.                  scr->dragInfo.location.x,
  1024.                  scr->dragInfo.location.y, &x, &y);
  1025.  
  1026.     view = findViewInToplevel(scr->display, 
  1027.                   scr->dragInfo.destinationWindow,
  1028.                   x, y);
  1029.     
  1030.     if (scr->dragInfo.destinationView != view) {
  1031.         WMView *oldVIew = scr->dragInfo.destinationView;
  1032.         
  1033.         oldView->dragDestinationProcs->draggingExited(oldView,
  1034.                               &scr->dragInfo);
  1035.         
  1036.         scr->dragInfo.destinationView = NULL;
  1037.     }
  1038.     
  1039.  
  1040.     if (IS_DROPPABLE(view)) {
  1041.         
  1042.         
  1043.         operation =
  1044.         view->dragDestinationProcs->draggingUpdated(view,
  1045.                                 &scr->dragInfo);
  1046.     }
  1047.     
  1048.     if (operation == 0) {
  1049.         sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
  1050.                   scr->xdndStatusAtom,
  1051.                   scr->dragInfo.destinationWindow,
  1052.                   0, 0, 0, None);
  1053.     } else {
  1054.         Atom action;
  1055.         
  1056.         switch (operation) {
  1057.          default:
  1058.         action = 0;
  1059.         break;
  1060.         }
  1061.  
  1062.         sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
  1063.                   scr->xdndStatusAtom,
  1064.                   scr->dragInfo.destinationWindow,
  1065.                   1, 0, 0, action);
  1066.     }
  1067.     
  1068.     } else if (event->message_type == scr->xdndLeaveAtom
  1069.            && scr->dragInfo.sourceWindow == event->data.l[0]) {
  1070.  
  1071.     void (*draggingExited)(WMView *self, WMDraggingInfo *info);
  1072.     
  1073.     puts("leave");
  1074.     } else if (event->message_type == scr->xdndDropAtom
  1075.            && scr->dragInfo.sourceWindow == event->data.l[0]) {
  1076.     
  1077.     
  1078.     
  1079.     puts("drop");
  1080.     }
  1081. #endif
  1082. }
  1083.  
  1084.